<?php
if (!defined('APP_ID')) { die('No direct script access allowed'); }

/**
 * Sending email
 */
class Email {
	const EOL = "\r\n";

	private $_driver = null;
	private $_from = array();
	private $_to = array();
	private $_cc = array();
	private $_bcc = array();
	private $_subject = '';
	private $_body = '';
	private $_charset = 'utf-8';

	public function __construct() {
		$this->_charset = Config::get('charset', 'email');

		if (!$this->_driver) {
			$driver = ucfirst(trim(strtolower(Config::get('driver', 'email'))));
			$class_name = 'Email_Driver_' . $driver;
			$this->_driver = new $class_name($this);
		}
	}

	/**
	 * Add sender
	 */
	public function from($email, $name = '', $visible = true) {
		$address = array();
		$address['email'] = $email;
		$address['name'] = $name;
		$address['visible'] = $visible;
		$this->_from[] = $address;
		return $this;
	}

	/**
	 * Add recipient
	 */
	public function to($email, $name = '', $visible = true) {
		$address = array();
		$address['email'] = $email;
		$address['name'] = $name;
		$address['visible'] = $visible;
		$this->_to[] = $address;
		return $this;
	}

	/**
	 * Add carbon copy
	 */
	public function cc($email, $name = '', $visible = true) {
		$address = array();
		$address['email'] = $email;
		$address['name'] = $name;
		$address['visible'] = $visible;
		$this->_cc[] = $address;
		return $this;
	}

	/**
	 * Add blind carbon copy
	 */
	public function bcc($email, $name = '', $visible = true) {
		$address = array();
		$address['email'] = $email;
		$address['name'] = $name;
		$address['visible'] = $visible;
		$this->_bcc[] = $address;
		return $this;
	}

	/**
	 * Set subject
	 */
	public function subject($text) {
		$this->_subject = $text;
		return $this;
	}

	/**
	 * Set body
	 */
	public function body($text) {
		$this->_body = $text;
		return $this;
	}

	/**
	 * Set body from file
	 */
	public function bodyFromFile($file_name) {
		$this->body(file_get_contents($file_name));
		return $this;
	}

	/**
	 * Build sender string
	 */
	public function getFrom($raw = false) {
		if ($raw) {
			return $this->_from;
		}
		
		$result = '';
		foreach ($this->_from as $address) {
			if (empty($address['email'])) { continue; }
			if (!$address['visible']) { continue; }
			if (!empty($result)) { $result .= ', '; }
			if (!empty($address['name'])) {
				$result .= $this->_encode($address['name']) . ' <' . $address['email'] . '>';
			} else {
				$result .= $address['email'];
			}
		}
		return $result;
	}

	/**
	 * Build recipient string
	 */
	public function getTo($raw = false) {
		if ($raw) {
			return $this->_to;
		}
		
		$result = '';
		foreach ($this->_to as $address) {
			if (empty($address['email'])) { continue; }
			if (!$address['visible']) { continue; }
			if (!empty($result)) { $result .= ', '; }
			if (!empty($address['name'])) {
				$result .= $this->_encode($address['name']) . ' <' . $address['email'] . '>';
			} else {
				$result .= $address['email'];
			}
		}
		return $result;
	}

	/**
	 * Build carbon copy string
	 */
	public function getCc($raw = false) {
		if ($raw) {
			return $this->_cc;
		}
		
		$result = '';
		foreach ($this->_cc as $address) {
			if (empty($address['email'])) { continue; }
			if (!$address['visible']) { continue; }
			if (!empty($result)) { $result .= ', '; }
			if (!empty($address['name'])) {
				$result .= $this->_encode($address['name']) . ' <' . $address['email'] . '>';
			} else {
				$result .= $address['email'];
			}
		}
		return $result;
	}

	/**
	 * Build blind carbon copy string
	 */
	public function getBcc($raw = false) {
		if ($raw) {
			return $this->_bcc;
		}
		
		$result = '';
		foreach ($this->_bcc as $address) {
			if (empty($address['email'])) { continue; }
			if (!$address['visible']) { continue; }
			if (!empty($result)) { $result .= ', '; }
			if (!empty($address['name'])) {
				$result .= $this->_encode($address['name']) . ' <' . $address['email'] . '>';
			} else {
				$result .= $address['email'];
			}
		}
		return $result;
	}

	/**
	 * Build headers string
	 */
	public function getHeaders($to_header = true) {
		$result = '';

		$from = $this->getFrom();
		$to = $this->getTo();
		$cc = $this->getCc();
		$bcc = $this->getBcc();

		if (!empty($from)) {
			$result .= 'From: ' . $from . self::EOL;
		}

		if (!empty($to) && $to_header) {
			$result .= 'To: ' . $to . self::EOL;
		}

		if (!empty($cc)) {
			$result .= 'Cc: ' . $cc . self::EOL;
		}

		if (!empty($bcc)) {
			$result .= 'Bcc: ' . $bcc . self::EOL;
		}

		$result .= 'MIME-Version: 1.0' . self::EOL;
		$result .= 'Content-type: text/html; charset=' . $this->_charset . self::EOL;
		$result .= 'Content-Transfer-Encoding: base64' . self::EOL;
		$result .= 'X-Mailer: PHP/' . phpversion();

		return $result;
	}

	/**
	 * Build subject string
	 */
	public function getSubject() {
		return $this->_encode($this->_subject);
	}

	/**
	 * Build body string
	 */
	public function getBody() {
		return $this->_encode($this->_body, true);
	}
	
	/**
	 * Encoding string
	 */
	private function _encode($in_str, $is_body = false) {
		$out_str = $in_str;
		if ($out_str) {
			if ($is_body) {
				$length = 68;
				$end = '';
				$start = '';
				$spacer = self::EOL;
			} else {
				// define start delimimter, end delimiter and spacer
				$end = '?=';
				$start = '=?' . $this->_charset . '?B?';
				$spacer = $end . self::EOL . $start;

				// determine length of encoded text within chunks
				// and ensure length is even
				$length = 75 - strlen($start) - strlen($end);

				/*
					[EDIT BY danbrown AT php DOT net: The following
					is a bugfix provided by (gardan AT gmx DOT de)
					on 31-MAR-2005 with the following note:
					"This means: $length should not be even,
					but divisible by 4. The reason is that in
					base64-encoding 3 8-bit-chars are represented
					by 4 6-bit-chars. These 4 chars must not be
					split between two encoded words, according
					to RFC-2047.
				*/
				$length = $length - ($length % 4);
			}

			// encode the string and split it into chunks
			// with spacers after each chunk
			$out_str = base64_encode($out_str);
			$out_str = chunk_split($out_str, $length, $spacer);

			// remove trailing spacer and
			// add start and end delimiters
			$spacer = preg_quote($spacer);
			$out_str = preg_replace('/' . $spacer . '$/', '', $out_str);
			$out_str = $start . $out_str . $end;
		}
		return $out_str;
	}

	/**
	 * Replace placeholders with values
	 */
	public function replaceArray($arr) {
		foreach ($arr as $key => $val) {
			$this->replace($key, $val);
		}
	}

	/**
	 * Replace placeholder with value
	 */
	public function replace($var, $val) {
		$this->_body = str_replace('{{' . $var . '}}', $val, $this->_body);
	}

	/**
	 * Perform sending
	 */
	public function send($clear = true) {
		$result = $this->_driver->send();		

		if ($clear) {
			$this->clear();
		}

		return $result;
	}

	/**
	 * Clear object
	 */
	public function clear() {
		$this->_from = array();
		$this->_to = array();
		$this->_cc = array();
		$this->_bcc = array();
		$this->_subject = '';
		$this->_body = '';
	}

}